rust
use std::cell::RefCell;
use std::rc::{Rc, Weak};

type AVLTreeNode = Rc<RefCell<Node>>;
type AVLTreeValue = i32; // Placeholder type, replace with actual value type

#[derive(Debug)]
struct Node {
    key: AVLTreeValue,
    value: AVLTreeValue,
    left: Option<AVLTreeNode>,
    right: Option<AVLTreeNode>,
    height: u32,
    parent: Option<Weak<RefCell<Node>>>,
}

struct AVLTree {
    root_node: Option<AVLTreeNode>,
    compare_func: fn(&AVLTreeValue, &AVLTreeValue) -> std::cmp::Ordering,
    num_nodes: usize,
}

impl AVLTree {
    fn new(compare_func: fn(&AVLTreeValue, &AVLTreeValue) -> std::cmp::Ordering) -> Self {
        AVLTree {
            root_node: None,
            compare_func,
            num_nodes: 0,
        }
    }

    // ... Other methods like `free`, `free_subtree`, `subtree_height`, etc. ...

    fn insert(&mut self, key: AVLTreeValue, value: AVLTreeValue) -> AVLTreeNode {
        // Placeholder for the actual insert logic
        // This should include updating heights and balancing the tree
        unimplemented!()
    }

    fn remove_node(&mut self, node: AVLTreeNode) {
        // Placeholder for the actual remove logic
        // This should update the tree and balance it
        unimplemented!()
    }

    fn remove(&mut self, key: AVLTreeValue) -> bool {
        // Placeholder for the actual remove logic
        // This should find the node and call remove_node
        unimplemented!()
    }

    fn lookup_node(&self, key: AVLTreeValue) -> Option<AVLTreeNode> {
        // Placeholder for the actual lookup logic
        // This should find a node with the given key
        unimplemented!()
    }

    fn lookup(&self, key: AVLTreeValue) -> Option<AVLTreeValue> {
        // Placeholder for the actual lookup logic
        // This should find a value associated with the given key
        unimplemented!()
    }

    // ... Other getters and utility functions ...
}

// Example usage of the AVLTree
fn main() {
    let mut avl_tree = AVLTree::new(|a, b| a.cmp(b));

    // Insert nodes
    let node = avl_tree.insert(10, 100);
    avl_tree.insert(20, 200);
    // ... More operations ...

    // Remove a node
    if avl_tree.remove(10) {
        println!("Node with key 10 removed.");
    }

    // Lookup a node
    if let Some(node) = avl_tree.lookup_node(20) {
        println!("Found node with key 20.");
    }
}

